#include "libBmp.h"
#include <stdio.h>
#include <cstring>
#include <stdlib.h>
#include <math.h>
#pragma pack(2)
#include <memory>

struct ImageProcess::RGN
{
    unsigned char Blue;
    unsigned char Green;
    unsigned char Red;
};

struct ImageProcess::ImageInfo
{
    unsigned int bmp_size;
    int bmp_width;
    int bmp_height;
    int bmp_bixpelspermeter;
    int bmp_biypelspermeter;
    bool negative;
    unsigned int bmp_offset;
    unsigned short int bmp_bitcount;
};

class ImageProcess::File_operator
{
public:
    FILE *fo,*fin;
    RGN rgb,black,white;
    char name[256];
    unsigned char temp[14];
    ImageInfo bmp;
public:
    //以下几个均为辅助函数
    void to_sit();//得到位图的像素的位置
    void get_wh();//得到位图的宽度、高度，单位为像素
    void get_size();
    void get_bi_xy_pelspermeter();
    void get_bitcount();//此函数留作支持1,4,8,位图的操作的支持，暂不使用
    void set_name(const char *filename,const char *new_name);
    void init();
    void open_files(const char *filename,const char *new_name);
    void close_files();
};



/**< 三个为私有函数 */
void ImageProcess::File_operator::set_name(const char *filename,const char *new_name)//new_name为新的原图片名称的后缀
{
    int len=strlen(filename);
    strcpy(name,filename);
    name[len-4]='\0';
    strcat(name,new_name);
    strcat(name,".bmp");
}

void ImageProcess::File_operator::init()
{
    black.Blue=black.Green=black.Red=0;
    white.Blue=white.Green=white.Red=255;
    bmp.bmp_height=bmp.bmp_offset=bmp.bmp_size=bmp.bmp_width=0;
}

void ImageProcess::File_operator::to_sit()
{
    fseek(fo,0,0);
    fseek(fo,10,0);
    fread(&(bmp.bmp_offset),4,1,fo);//读取像素的偏移位置
    fseek(fo,0,0);//偏移到初始的位置
}

void ImageProcess::File_operator::get_wh()
{
    fseek(fo,0,0);
    fseek(fo,18,0);//获取bmp图片的宽度
    fread(&(bmp.bmp_width),4,1,fo);
    fseek(fo,0,0);
    fseek(fo,22,0);//获取bmp图片的高度
    fread(&(bmp.bmp_height),4,1,fo);
    fseek(fo,0,0);
    if(bmp.bmp_height<0)
    {
        bmp.bmp_height=-1*bmp.bmp_height;
        bmp.negative=true;
    }
    else bmp.negative=false;
}

void ImageProcess::File_operator::get_bi_xy_pelspermeter()
{
    fseek(fo,0,0);
    fseek(fo,38,0);
    fread(&(bmp.bmp_bixpelspermeter),4,1,fo);// 位图水平分辨率，每米像素数
    fread(&(bmp.bmp_biypelspermeter),4,1,fo);// 位图垂直分辨率，每米像素数
    fseek(fo,0,0);
}

void ImageProcess::File_operator::get_size()
{
    fseek(fo,0,0);
    fseek(fo,14,0);
    fread(&(bmp.bmp_size),4,1,fo);
    fseek(fo,0,0);
}

void ImageProcess::File_operator::get_bitcount()
{
    fseek(fo,0,0);
    fseek(fo,28,0);
    fread(&(bmp.bmp_bitcount),2,1,fo);
    fseek(fo,0,0);
}

void ImageProcess::File_operator::close_files()
{
    fclose(fo);
    fclose(fin);
}

void ImageProcess::File_operator::open_files(const char *filename,const char *new_name)
{
    if((fo=fopen(filename,"rb+"))==NULL)
    {
        printf("can not open %s",filename);
        exit(0);
    }
    //设置新的图片文件名
    set_name(filename,new_name);
    if((fin=fopen(name,"wb+"))==NULL)
    {
        printf("can not open %s",name);
        exit(0);
    }
}

ImageProcess::ImageProcess()
{
    file_operator=new File_operator();
    file_operator->init();
}

/**< 以下代码为接口 */
void ImageProcess::to_baw(const char *filename,const char *new_name)
{
    file_operator->open_files(filename,new_name);
    file_operator->to_sit();
    unsigned int i=1;

    //将头文件中信息复制下来
    while(i<=file_operator->bmp.bmp_offset)
    {
        fread(file_operator->temp,1,1,file_operator->fo);
        fwrite(file_operator->temp,1,1,file_operator->fin);
        i+=1;
    }
    //对像素的值进行设置成0 或 255
    while(!feof(file_operator->fo))
    {
        ++i;
        fread(&(file_operator->rgb),3,1,file_operator->fo);
        if((file_operator->rgb.Blue+file_operator->rgb.Green+file_operator->rgb.Red)/3<125)
            fwrite(&(file_operator->black),3,1,file_operator->fin);
        else
            fwrite(&(file_operator->white),3,1,file_operator->fin);
    }
    file_operator->close_files();
}

void ImageProcess::to_transpose(const char *filename,const char *new_name,bool clock_direction)
{
    //printf("is opening bmp\n");
    file_operator->open_files(filename,new_name);
    file_operator->get_wh();//获取原bmp图片的大小，存放在bmp_info结构体中
    file_operator->get_bi_xy_pelspermeter();
    //printf("create a double-dimensional array\n");
    RGN **bmp_temp=(RGN **)malloc(file_operator->bmp.bmp_height*sizeof(RGN *));
    for( int i=0; i<file_operator->bmp.bmp_height; ++i)
    {
        bmp_temp[i]=(RGN *)malloc(file_operator->bmp.bmp_width*sizeof(bmp_temp));
    }

    int row_temp=file_operator->bmp.bmp_width,column_temp=file_operator->bmp.bmp_height;
    if(row_temp%4!=0)
    {
        row_temp=row_temp+(4-row_temp%4);
    }
    if(column_temp%4!=0)
    {
        column_temp=column_temp+(4-column_temp%4);
    }
    //创建一个二维数组
    RGN **bmp_temp_new=(RGN **)malloc(row_temp*sizeof(RGN *));
    for(int i=0; i<row_temp; ++i)
    {
        bmp_temp_new[i]=(RGN *)malloc(column_temp*sizeof(bmp_temp_new));
    }

    file_operator->to_sit();//移动到像素开始的位置

   // printf("copy inof of head file,%d of size\n",file_operator->bmp.bmp_offset);
    unsigned int i=0;
    while(i<=file_operator->bmp.bmp_offset)
    {
        fread(file_operator->temp,1,1,file_operator->fo);
        fwrite(file_operator->temp,1,1,file_operator->fin);
        i+=1;
        switch(i)
        {
        case 18:
        {
            if(file_operator->bmp.negative)
                row_temp=row_temp*-1;
            //printf("reseting info of head file \n");
            if(fwrite(&(column_temp),4,1,file_operator->fin)!=1||fwrite(&(row_temp),4,1,file_operator->fin)!=1)
            {
            //    printf("reseting info of head file error\n");
                exit(0);
            }
            fseek(file_operator->fo,8,1);
            i+=8;
        }
        break;
        case 38:
        {
            if(fwrite(&(file_operator->bmp.bmp_biypelspermeter),4,1,file_operator->fin)!=1||fwrite(&(file_operator->bmp.bmp_bixpelspermeter),4,1,file_operator->fin)!=1)
            {
                printf("reseting info of head file error\n");
                exit(0);
            }
            fseek(file_operator->fo,8,1);
            i+=8;
        }
        break;
        }
    }
    //printf("bmp_height=%d,bmp_weight=%d\n",file_operator->bmp.bmp_height,file_operator->bmp.bmp_width);

    int row=0;
    //printf("reading content of bmp write to bmp_temp\n");
    for(row=0; row < file_operator->bmp.bmp_height; ++row)
    {
        if(fread(bmp_temp[row], file_operator->bmp.bmp_width*sizeof(RGN),1,file_operator->fo)!=1)
            exit(0);
    }

    int percent=(int)file_operator->bmp.bmp_height*0.05;
    //printf("***left90***\n");
    printf("doing:[");
    switch(clock_direction)
    {
    case false:
    {
        for(row=0 ; row< file_operator->bmp.bmp_height; ++row)
        {
            for(int column =0; column < file_operator->bmp.bmp_width; ++column)
            {
                bmp_temp_new[file_operator->bmp.bmp_width-1-column][row]=bmp_temp[row][column];
            }
            if(row%percent==0)
                printf("#");
        }
    }
    break;
    case true:
    {
        for(row=0 ; row< file_operator->bmp.bmp_height; ++row)
        {
            for(int column =0; column <file_operator->bmp.bmp_width; ++column)
            {
                bmp_temp_new[column][file_operator->bmp.bmp_height-1-row]=bmp_temp[row][column];
            }
            if(row%percent==0)
                printf("#");
        }
    }
    }

    printf("]\n");
    //printf("***bmp temp new now***\n");
    for(row=2; row<row_temp; ++row)
        fwrite(bmp_temp_new[row],column_temp*sizeof(RGN),1,file_operator->fin);
    fwrite(bmp_temp_new[1],column_temp*sizeof(RGN),1,file_operator->fin);
    fwrite(bmp_temp_new[0],column_temp*sizeof(RGN),1,file_operator->fin);

    //printf("is clear memory\n");
    for(row=0; row < file_operator->bmp.bmp_height; ++row)
    {
        free(bmp_temp[row]);
    }
    free(bmp_temp);
    for(row=0; row < row_temp; ++row)
    {
        free(bmp_temp_new[row]);
    }
    free(bmp_temp_new);
    file_operator->close_files();
}

void ImageProcess::to_mirror(const char *filename,const char *new_name,bool mirros_direction)
{
    file_operator->open_files(filename,new_name);
    file_operator->get_wh();
    file_operator->to_sit();

    //printf("create double dimensional array\n");
    RGN **bmp_temp=(RGN **)malloc(file_operator->bmp.bmp_height*sizeof(RGN *));
    for( int i=0; i<file_operator->bmp.bmp_height; ++i)
    {
        bmp_temp[i]=(RGN *)malloc(file_operator->bmp.bmp_width*sizeof(bmp_temp));
    }
    //创建一个二维数组
    RGN **bmp_temp_new=(RGN **)malloc(file_operator->bmp.bmp_height*sizeof(RGN *));
    for( int i=0; i<file_operator->bmp.bmp_height; ++i)
    {
        bmp_temp_new[i]=(RGN *)malloc(file_operator->bmp.bmp_width*sizeof(bmp_temp_new));
    }

    //将头文件中信息复制下来
    unsigned int i=1;
    while(i<=file_operator->bmp.bmp_offset)
    {
        fread(file_operator->temp,1,1,file_operator->fo);
        fwrite(file_operator->temp,1,1,file_operator->fin);
        i+=1;
    }

    //printf("bmp_height=%d,bmp_weight=%d\n",file_operator->bmp.bmp_height,file_operator->bmp.bmp_width);

    int row=0;
    for(row=0; row < file_operator->bmp.bmp_height; ++row)
    {
        if(fread(bmp_temp[row], file_operator->bmp.bmp_width*sizeof(RGN),1,file_operator->fo)!=1)
            exit(0);
    }
    int percent=(int)file_operator->bmp.bmp_height*0.05;
    printf("doing:[");
    switch(mirros_direction)
    {
    case false:
    {
        for(row=0 ; row< file_operator->bmp.bmp_height; ++row)
        {
            for(int column =0; column <file_operator->bmp.bmp_width; ++column)
            {
                bmp_temp_new[row][file_operator->bmp.bmp_width-1-column]=bmp_temp[row][column];
            }
            if(row%percent==0)
                printf("#");
        }
    }
    break;
    case true:
    {
        for(row=0 ; row< file_operator->bmp.bmp_height; ++row)
        {
            bmp_temp_new[file_operator->bmp.bmp_height-1-row]=bmp_temp[row];
            if(row%percent==0)
                printf("#");
        }
    }
    break;
    }

    printf("]\n");
    //printf("***bmp temp new now***\n");
    for(row=1; row<file_operator->bmp.bmp_height; ++row)
        fwrite(bmp_temp_new[row],file_operator->bmp.bmp_width*sizeof(RGN),1,file_operator->fin);
    fwrite(bmp_temp_new[0],file_operator->bmp.bmp_width*sizeof(RGN),1,file_operator->fin);
    for(row=0; row < (int)abs(file_operator->bmp.bmp_height); ++row)
    {
        free(bmp_temp[row]);
        /**< 如果不进行判断，指针会重复关闭 ，因为这与算法有关*/
        if(!mirros_direction)
        {
            free(bmp_temp_new[row]);
        }
    }
    free(bmp_temp);
    free(bmp_temp_new);
    file_operator->close_files();
    //printf("over\a");
}
